package cloud.tianai.ram.policy.server.condition.impl;

import cloud.tianai.ram.policy.common.model.dto.Match;
import cloud.tianai.ram.policy.common.model.dto.Statement;
import cloud.tianai.ram.policy.common.model.dto.Action;
import cloud.tianai.ram.policy.common.handler.ConditionHandler;
import cloud.tianai.ram.policy.common.handler.ConditionHandlerManager;
import cloud.tianai.ram.policy.common.exception.ConditionHandlerNotFoundException;
import cloud.tianai.ram.policy.common.model.dto.Condition;
import cloud.tianai.ram.policy.common.model.dto.TypeDefinition;
import cloud.tianai.ram.policy.server.condition.impl.handler.AndConditionHandler;
import cloud.tianai.ram.policy.server.condition.impl.handler.OrConditionHandler;
import cloud.tianai.ram.policy.server.condition.impl.handler.XorConditionHandler;
import org.springframework.util.CollectionUtils;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

/**
 * @Author: 天爱有情
 * @date 2022/3/7 14:04
 * @Description 默认的条件处理程序管理器
 */
public class DefaultConditionHandlerManager implements ConditionHandlerManager {

    private List<ConditionHandler> conditionHandlerList = new ArrayList<>(32);

    public DefaultConditionHandlerManager() {
        addDefaultConditionHandler();
    }

    public void addDefaultConditionHandler() {
        // and
        addConditionHandler(new AndConditionHandler());
        // or
        addConditionHandler(new OrConditionHandler());
        // xor
        addConditionHandler(new XorConditionHandler());
    }

    @Override
    public void addConditionHandler(ConditionHandler condition) {
        conditionHandlerList.add(condition);
    }

    @Override
    public ConditionHandler getConditionHandler(String operationType) {
        for (ConditionHandler conditionHandler : conditionHandlerList) {
            if (conditionHandler.support(operationType)) {
                return conditionHandler;
            }
        }
        return null;
    }

    @Override
    public ConditionHandler getConditionHandler(Condition condition) {
        for (ConditionHandler conditionHandler : conditionHandlerList) {
            if (conditionHandler.support(condition)) {
                return conditionHandler;
            }
        }
        return null;
    }

    @Override
    public List<TypeDefinition> listSupportedTypes() {
        List<TypeDefinition> list = new ArrayList<>(conditionHandlerList.size());
        for (ConditionHandler conditionHandler : conditionHandlerList) {
            list.addAll(conditionHandler.listSupportTypes());
        }
        return list;
    }

    @Override
    public boolean removeConditionHandler(String operationType) {
        return conditionHandlerList.removeIf(c -> c.support(operationType));
    }

    @Override
    public Collection<ConditionHandler> getConditionHandlers() {
        return conditionHandlerList;
    }

    @Override
    public Match match(List<Condition> conditionList, Action action) throws ConditionHandlerNotFoundException {
        for (Condition condition : conditionList) {
            Match match = match(condition, action);
            if (match.isDeny()) {
                return match;
            }
        }
        return Match.ALLOW;
    }

    @Override
    public Match match(Condition condition, Action action) throws ConditionHandlerNotFoundException {
        ConditionHandler conditionHandler = getConditionHandler(condition.getOperationType());
        if (conditionHandler == null) {
            throw new ConditionHandlerNotFoundException(condition.getOperationType() + " handler not found");
        }
        if (!conditionHandler.match(condition, this, action)) {
            return Match.EXPLICIT_DENY;
        }
        return Match.ALLOW;
    }

    @Override
    public Match handle(Action action, Statement statement) {
        List<Condition> conditionList = statement.getConditionList();
        if (CollectionUtils.isEmpty(conditionList)) {
            return Match.ALLOW;
        }
        return match(conditionList, action);
    }
}
